package org.wattdepot.simulation.oahugrid.powerplant;

import java.util.Calendar;
import org.wattdepot.simulation.oahugrid.strategy.SimulationEntry;

/**
 * Represents all of the power generation plants in this simulation.
 * Note the following table of plants, capacities, and carbon intensities:
 * <pre>
 * Plant(s)     Capacity    Carbon   Type
 * Waiau 9-10     100        2,400   Peaking
 * Honolulu 8-9   105        2,240   Cycling
 * AES            180        2,120   Baseload
 * Kalaeloa       200        2,050   Baseload
 * Waiau 5-6      108        1,800   Cycling
 * Waiau 7-8      184        1,800   Baseload
 * Kahe 1-6       595        1,744   Baseload 
 * HPOWER          45          150   Baseload
 * </pre>

 * @author Philip Johnson
 */
public enum PowerPlant {
  /** The Kahe baseload plants. */
  SIM_KAHE_1 (Type.BASELOAD, 88, 8, 4),
  /** The Kahe baseload plants. */
  SIM_KAHE_2 (Type.BASELOAD, 88, 8, 4),
  /** The Kahe baseload plants. */
  SIM_KAHE_3 (Type.BASELOAD, 88, 8, 4),
  /** The Kahe baseload plants. */
  SIM_KAHE_4 (Type.BASELOAD, 88, 8, 4),
  /** The Kahe baseload plants. */
  SIM_KAHE_5 (Type.BASELOAD, 88, 8, 4),
  /** The Kahe baseload plants. */
  SIM_KAHE_6 (Type.BASELOAD, 135, 20, 8),
  /** The Kahe spinning reserve plant. */
  SIM_KAHE_7 (Type.SPINNINGRESERVE, 135, 20, 8),
  /** The Waiau baseload plants. */
  SIM_WAIAU_7 (Type.BASELOAD, 88, 8, 4),
  /** The Waiau baseload plants. */
  SIM_WAIAU_8 (Type.BASELOAD, 88, 8, 4),
  /** The HPOWER baseload plant. */
  SIM_HPOWER (Type.BASELOAD, 46, 5, 5),
  /** The AES baseload plant. */
  SIM_AES (Type.BASELOAD, 180, 20, 5),
  /** The Kalaeloa baseload plant. */
  SIM_KALAELOA (Type.BASELOAD, 200, 20, 5),
  /** The Waiau cycling plants. */
  SIM_WAIAU_5 (Type.CYCLING, 54, 0, 0),
  /** The Waiau cycling plants. */
  SIM_WAIAU_6 (Type.CYCLING, 54, 0, 0),
  /** The Honolulu cycling plants. */
  SIM_HONOLULU_8 (Type.CYCLING, 53, 0, 0),
  /** The Honolulu cycling plants. */
  SIM_HONOLULU_9 (Type.CYCLING, 53, 0, 0),
  /** The Waiau peaking plant. */
  SIM_WAIAU_9 (Type.PEAKING, 51, 0, 0),
  /** The Waiau peaking plant. */
  SIM_WAIAU_10 (Type.PEAKING, 51, 0, 0);

  /** Each power generator must be one of the following types. */
  public enum Type { BASELOAD, CYCLING, PEAKING, SPINNINGRESERVE };
  
  /** The type of this power plant. */
  private Type type;
  /** The maximum MW that this plant can produce. */
  private int maxMW;
  /** The minimum MW that this plant can produce. Baseload plants have a non-zero minimum.*/ 
  //private int minMW;
  /** The amount of MW generated by this plant that goes to running the plant. */
  private int overheadMW;
  /** The total energy generated by this plant so far. */
  private double energyGeneratedToDate = 0;


  /**
   * Creates a new power plant with given specifications.
   * @param type The type of plant.
   * @param maxMW The maximum MW output.
   * @param minMW The minimum MW output. 
   * @param overheadMW The MW used for overhead.
   */
  private PowerPlant(Type type, int maxMW, int minMW, int overheadMW) {
    this.type = type;
    this.maxMW = maxMW;
    //this.minMW = minMW;
    this.overheadMW = overheadMW;
  }
  
  /**
   * Returns the type of plant.
   * @return The type.
   */
  public Type getType() {
    return this.type;
  }
  
  /**
   * Given a request for power in MW, return the amount of MW that this plant can provide. 
   * Requests for 0 or negative MW return 0;
   * @param requestedMW The requested amount of power.
   * @return The power that this plant can provide, in MW. 
   */
  public int provideMW(int requestedMW) {
    if (requestedMW <= 0) {
      return 0;
    }
    else if (requestedMW > maxMW) {
      return maxMW;
    }
    /*  Don't do minimums now, too confusing.
    else if (requestedMW < minMW) {
      return minMW;
    }
    */
    else {
      return requestedMW;
    }
  }
  
  /**
   * Returns the MW generated for overhead.
   * @return The overhead power.
   */
  public int getOverheadMW() {
    return this.overheadMW;
  }
  
  /**
   * Returns the maximum MW this plant can provide to the grid.
   * @return The maximum power.
   */
  public int getMaxMW() {
    return this.maxMW;
  }

  /**
   * Returns a SimulationEntry for this power plant. The plant will provide as much of the 
   * requestedMW as it can.
   * Note that this method does not take into account minMW, overhead, or spinning reserve.
   * @param requestedMW The requested MW. This can be zero, in which case the power plant
   * creates an entry indicating its overhead power.
   * @param timestamp The timestamp when power is required.
   * @return The SimulationEntry instance representing the power provided by this plant.
   */
  public SimulationEntry getSimulationEntry(int requestedMW, Calendar timestamp) {
    return new SimulationEntry(timestamp.getTimeInMillis(), this, 
        this.provideMW(requestedMW), this.overheadMW);
  }

  /**
   * Updates this plant's total generated energy by additional energy.
   * @param additionalEnergy The additional energy (in MWh) to be added.
   */
  public void incrementEnergyGeneratedToDate(long additionalEnergy) {
    this.energyGeneratedToDate += additionalEnergy;
  }

  /** 
   * Returns the total energy generated by this plant so far in the simulation. 
   * @return The total energy. 
   */
  public double getEnergyGeneratedToDate() {
    return energyGeneratedToDate;
  }
  
  /**
   * Provide an initial value for energy generated for this PowerPlant. It should be 
   * retrieved from WattDepot.
   * @param energy The initial energy generated value. 
   */
  public void initializeEnergyGeneratedToDate(Double energy) {
    this.energyGeneratedToDate = energy;
    
  }

}
